
from core.task import Task,Task_Config
import pandas as pd
import numpy as np
from collections import namedtuple

class Plane(object):
    """
    飞机类，保障的各种任务前后关系与约束
    通过dag表示node之间的关系
    
    """
    # node_cls = Node
    task_dataframe = None


    def __init__(self, env, plane_config):
        self.env = env
        # self.event = event
        self.plane_config = plane_config
        self.id = plane_config.id
        # self.task_dataframe = task_dataframe
        # self.task_dag = []
        # :从xml 读取node到nodes_map
        # impliments
        self.tasks = []
        self.task_map = dict()
        self.dag_map = dict()
        self.sub_tasks()
        self.generate_tasks_dependency()


        assert len(self.task_map) != 0
        # for task_config in plane_config.task_configs:
        #     node_index = node_config.node_index
        #     self.nodes_map[node_index] = Plane.node_cls(env, self, node_config)

    def reset(self,env):
        self.env = env
        for task in self.tasks:
            task.reset()


    def sub_tasks(self):
        #todo:根据plane-config和task_dataframe生成task实例

        df = Plane.task_dataframe

        for i in range(len(df)):
            task_parameter = df.iloc[i]
            task_config = Task_Config(task_parameter.task_id,task_parameter.task_type,\
                                      task_parameter.typename,task_parameter.duration,\
                                      task_parameter.worker_type,task_parameter.layer)
            task = Task(self.env,task_config)
            # attach plane
            task.attach(self)

            self.tasks.append(task)

            ## dependency
            task_parent = task_parameter.parent.split('/')
            task_parent = [] if task_parent[0] == '0' else task_parent

            task_child = task_parameter.child
            task_child = None if task_child == 0 else task_child

            Prepost = namedtuple('Prepost','parents child')

            self.task_map[task_config.task_id] = task
            self.dag_map[task_config.task_id] = Prepost(parents=task_parent,child=task_child)


        # return node_list
    def generate_tasks_dependency(self):
        # children = self.collection.getElementsByTagName("child")
        # dependencies = {}

        for id,task in self.task_map.items():
            parents_id,child_id = self.dag_map[id].parents,self.dag_map[id].child

            for p_id in parents_id:
                task.parents.append(self.task_map[int(p_id)])

            task.child = None if child_id is None else self.task_map[child_id]



        # return dependencies

    @property
    def all_tasks(self):
        return self.tasks

    @property
    def unfinished_tasks(self):
        ls = []
        for task in self.tasks:
            if not task.finished:
                ls.append(task)
        return ls

    @property
    def ready_unstarted_tasks(self):
        ls = []
        for task in self.tasks:
            if not task.started and task.ready:
                ls.append(task)
        return ls

    @property
    def running_tasks(self):
        ls = []
        for task in self.tasks:
            if task.started and not task.finished:
                ls.append(task)
        return ls

    @property
    def finished_tasks(self):
        ls = []
        for task in self.tasks:
            if task.finished:
                ls.append(task)
        return ls

    @property
    def started(self):
        for task in self.tasks:
            if task.tasks:
                return True
        return False

    @property
    def finished(self):
        for task in self.tasks:
            if not task.finished:
                return False
        return True

    @property
    def unreleased_tasks(self):
        ls = []
        for task in self.tasks:

            if not task.ready:
                ls.append(task)
        return ls

    @property
    def started_timestamp(self):
        t = None
        for task in self.tasks:
            if task.started_timestamp is not None:
                if (t is None) or (t > task.started_timestamp):
                    t = task.started_timestamp
        return t

    @property
    def finished_timestamp(self):
        if not self.finished:
            return None
        t = None
        for task in self.tasks:
            if (t is None) or (t < task.finished_timestamp):
                t = task.finished_timestamp
        return t

    def __str__(self) -> str:
        return "plane{"+"id="+self.id+"}"

    def unready_layer_taskInfo(self) -> np.ndarray:
        '''解决每个飞机未释放节点的关系层次'''
        workertype_dict = {'kp1': 0, 'kp2': 1, 'kp3': 2, 'kp4': 3}
        # info = dict()
        graph_info = np.zeros((16), dtype=np.float32)
        for task in self.tasks:
            if task.layer > 0:
                # task.layer = task.duration,task.worker_type
                # info[(task.layer,task.worker_type)] = info.get((task.layer,task.worker_type), default=0)+task.duration /12
                graph_info[task.layer*4+ workertype_dict[task.worker_type]] += task.duration / 12

        return graph_info
